﻿using System.Reflection;
using Microsoft.Extensions.DependencyInjection;

namespace ORS.OrderRobot.IOC
{
    public static class ServiceCollectionExtensions
    {
        /// <summary>
        /// 递归加载入口程序集及其引用程序集
        /// </summary>
        public static Assembly[] LoadEntryAndReferencedAssemblies(Assembly entryAssembly)
        {
            var assemblies = new List<Assembly>();
            var visited = new HashSet<string>();

            void LoadRecursively(Assembly asm)
            {
                if (visited.Contains(asm.FullName)) return;
                visited.Add(asm.FullName);
                assemblies.Add(asm);

                foreach (var reference in asm.GetReferencedAssemblies())
                {
                    try
                    {
                        var referencedAssembly = Assembly.Load(reference);
                        LoadRecursively(referencedAssembly);
                    }
                    catch
                    {
                        // 失败忽略
                    }
                }
            }

            LoadRecursively(entryAssembly);
            return assemblies.ToArray();
        }

        /// <summary>
        /// 自动扫描程序集并注册依赖
        /// </summary>
        public static IServiceCollection AddAutoInject(this IServiceCollection services, params Assembly[] assemblies)
        {
            if (assemblies == null || assemblies.Length == 0)
            {
                assemblies = LoadEntryAndReferencedAssemblies(Assembly.GetEntryAssembly());
            }
            var orsAssemblies = assemblies.Where(a => a.FullName.Contains("ORS")).ToArray();

            foreach (var type in orsAssemblies.SelectMany(a => a.GetTypes()))
            {
                if (!type.IsClass || type.IsAbstract) continue;

                var interfaces = type.GetInterfaces();

                if (typeof(IScoped).IsAssignableFrom(type))
                {
                    services.AddScoped(type);
                    foreach (var iface in interfaces.Where(i => i != typeof(IScoped)))
                    {
                        services.AddScoped(iface, sp => sp.GetRequiredService(type));
                    }
                }
                else if (typeof(ITransient).IsAssignableFrom(type))
                {
                    services.AddTransient(type);
                    foreach (var iface in interfaces.Where(i => i != typeof(ITransient)))
                    {
                        services.AddScoped(iface, sp => sp.GetRequiredService(type));
                    }
                }
                else if (typeof(ISingleton).IsAssignableFrom(type))
                {
                    // 先注册具体类型
                    services.AddSingleton(type);

                    // 用工厂方法注册接口，确保注入同一实例
                    foreach (var iface in interfaces.Where(i => i != typeof(ISingleton)))
                    {
                        services.AddSingleton(iface, sp => sp.GetRequiredService(type));
                    }
                }
            }

            return services;
        }
    }
}
